package com.cpkso.buss.backend.security;

import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.druid.util.Base64;
import com.cpkso.buss.backend.user.domain.Permission;
import com.cpkso.buss.backend.user.domain.Role;
import com.cpkso.buss.backend.user.domain.User;
import com.cpkso.buss.backend.user.service.UserService;
import com.runze.base.web.Response;

/**
 * @author wrzhxy@qq.com
 * @date 2017年12月28日
 */
@Component
public class AuthRealm extends AuthorizingRealm {

	@Autowired
    protected UserService userService;

    public AuthRealm() {
        setName("AuthRealm");		//This name must match the name in the User class's getPrincipals() method
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
        hashedCredentialsMatcher.setHashIterations(1024);
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(false);	// 这一行决定hex还是base64
        setCredentialsMatcher(hashedCredentialsMatcher);
    }
    
    /**
     * 授权验证
     * 
     * 验证的用户信息只是登录时从数据库取出后的对象。
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权验证");
		//获取当前登录输入的用户名，等价于(String) principalCollection.fromRealm(getName()).iterator().next();
		String loginName = (String)super.getAvailablePrincipal(principals);
		// 到数据库查是不是有此对象
		Response response = userService.findByNameAndValid(loginName);
		User user = (User) response.getData();
System.out.println("login name: " + loginName);		
		if (user != null) {
			// 权限信息对象info，用来存放查出的用户的所有角色和权限
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			// 用户的角色集合
			Set<String> roles = new HashSet<>();
			Set<Role> roles_db = user.getRoles();
			for (Role r : roles_db) {
				roles.add(r.getName());
				// 用户的角色对应的所有权限，如果只使用角色定义访问权限，下面可以不要
				// 遍历角色，获取权限
//				info.addStringPermission("fuck:666");
				Set<Permission> permissions = r.getPermissions();
				Set<String> permissions_str = new HashSet<>();
				for (Permission permission : permissions)
					permissions_str.add(permission.getName());
				info.addStringPermissions(permissions_str);	// 会将整个集合添加到
			}
			info.setRoles(roles);
System.out.println("authorization finished");
			return info;
		} else return null;
    }
    
    /**
     * 登录验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("登录验证");
    	// UsernamePasswordToken对象用来存放提交的登录信息
        UsernamePasswordToken upt = (UsernamePasswordToken) token;
        
        // 查出是否有此用户
        String username_upt = upt.getUsername();
        Response response = userService.findByNameAndValid(username_upt);
        User user = (User) response.getData();
        
        if (user != null) {
        	// 若存在，将此用户存放到登录认证info中，无需自己做密码对比，Shiro会为我们进行密码对比校验
        	// 第三个插入盐
        	// TODO 记录ip 时间
        	ByteSource bytes = ByteSource.Util.bytes(Base64.base64ToByteArray(user.getSalt()));
        	SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getName(), user.getPassword(), bytes, getName());
System.out.println(info);
            return info;
        }
    	return null;
    }

}
